module uart(
    input clk,
    input rst_n,
    input din,
    output reg dout
);
    
    reg [31:0] freg = 32'h0096FEB5; //波特率计算：freg = (f_bit * 2^32)/f_clk
    reg clken, clkot;
    reg [1 :0] creg, oreg;
    reg [1 :0] clkr, clko;
    reg [8 :0] dbuf;
    reg [9 :0] dreg;
    reg [31:0] cnt0, cnt1;
    reg [31:0] cnt2, cnt3;
    
    //串口接收控制
    always @(posedge clk, negedge rst_n) begin
        if (!rst_n) begin
            clken <= 1'b0;
            clkr <= 2'b0;
            creg <= 2'b0;
            cnt0 <= 32'b0;
        end
        else begin
            creg[0] <= din;
            creg[1] <= creg[0];
            if (creg[1]&(!creg[0])) clken <= 1'b1;
            else if (cnt1==10) clken <= 1'b0;
            if (clken) cnt0 <= cnt0 + freg;
            else cnt0 <= 32'b0;
            clkr[0] <= cnt0[31];
            clkr[1] <= clkr[0];
        end
    end
    
    //串口接收数据
    always @(posedge clk, negedge rst_n) begin
        if (!rst_n) begin
            dbuf <= 9'b0;
            cnt1 <= 32'b0;
        end
        else begin
            if ((!clkr[1])&clkr[0]) begin
                dbuf <= {creg[1], dbuf[8:1]};
                cnt1 <= cnt1 + 1'b1;
            end
            else if (!clken) begin
                cnt1 <= 32'b0;
            end
        end
    end
    
    //串口发送控制
    always @(posedge clk, negedge rst_n) begin
        if (!rst_n) begin
            clkot <= 1'b0;
            clko <= 2'b0;
            oreg <= 2'b0;
            cnt2 <= 32'b0;
        end
        else begin
            oreg[0] <= clken;
            oreg[1] <= oreg[0];
            if (oreg[1]&(!oreg[0])) begin
                clkot <= 1'b1;
            end
            else if (cnt3==11)
                clkot <= 1'b0;
            if (clkot) cnt2 <= cnt2 + freg;
            else cnt2 <= 32'b0;
            clko[0] <= cnt2[31];
            clko[1] <= clko[0];
        end
    end
    
    //串口发送数据
    always @(posedge clk, negedge rst_n) begin
        if (!rst_n) begin
            dout <= 1'b1;
            dreg <= 10'b0;
            cnt3 <= 32'b0;
        end
        else begin
            if (oreg[1]&(!oreg[0])) begin
                dreg <= {dbuf, 1'b0};
            end
            else if ((!clko[1])&clko[0]) begin
                dout <= dreg[0];
                dreg <= {1'b1, dreg[9:1]};
                cnt3 <= cnt3 + 1'b1;
            end
            else if (!clkot) begin
                dout <= 1'b1;
                cnt3 <= 32'b0;
            end
        end
    end
    
endmodule 